package com.weifly.weistock.record.option;

import com.weifly.weistock.core.common.StockException;
import com.weifly.weistock.core.util.WeistockUtils;
import com.weifly.weistock.record.base.domain.RecordPair;
import com.weifly.weistock.record.option.OptionConst;
import com.weifly.weistock.record.option.OptionUtils;
import com.weifly.weistock.record.option.domain.OptionRecordDto;

import java.util.ArrayList;
import java.util.List;

/**
 * 计算合约上下文
 *
 * @author weifly
 * @since 2019/11/27
 */
public class CalcContractContext {

    private int pairIndex = 1; // pair的索引值
    private List<RecordPair> pairList = new ArrayList<>(); // 匹配的pair列表

    private OptionRecordDto currRecord; // 当前记录
    private OptionConst.OperationType currOperationType; // 当前记录ot
    private int currTradeNumber; // 当前记录 剩余未配对数量

    public void initRecord(OptionRecordDto recordDto){
        OptionConst.OperationType ot = recordDto.getOperationType();
        if(OptionUtils.isCloseRecord(recordDto)){
            this.pairList.clear();
            this.currRecord = recordDto;
            this.currOperationType = ot;
            this.currTradeNumber = recordDto.getTradeNumber();
        }else{
            throw new StockException("不支持的operationType, " + ot);
        }
    }

    public void buildPair(OptionRecordDto preRecord){
        // 没有“未配对”记录
        if(this.currTradeNumber<=0){
            return;
        }

        // 跳过 行权指派
        if(OptionConst.BusinessName.NAME_9.equals(preRecord.getBusinessName())){
            return;
        }

        // 备兑开仓 - 备兑平仓
        if(OptionConst.OperationType.TYPE_2.equals(this.currOperationType)){
            if(!OptionConst.OperationType.TYPE_1.equals(preRecord.getOperationType())){
                return;
            }
        }
        // 卖出开仓 - 买入平仓
        else if(OptionConst.OperationType.TYPE_4.equals(this.currOperationType)){
            if(!OptionConst.OperationType.TYPE_5.equals(preRecord.getOperationType())){
                return;
            }
        }
        // 买入开仓 - 卖出平仓
        else if(OptionConst.OperationType.TYPE_6.equals(this.currOperationType)){
            if(!OptionConst.OperationType.TYPE_3.equals(preRecord.getOperationType())){
                return;
            }
        }
        // (卖出开仓认沽，买入开仓认购) - 买入
        else if(OptionConst.OperationType.TYPE_7.equals(this.currOperationType)){
            boolean sellPut = (preRecord.getContractName().indexOf("沽")!=-1 && OptionConst.OperationType.TYPE_5.equals(preRecord.getOperationType()));
            boolean buyCall = (preRecord.getContractName().indexOf("购")!=-1 && OptionConst.OperationType.TYPE_3.equals(preRecord.getOperationType()));
            if(!sellPut && !buyCall){
                return;
            }
        }else{
            return;
        }

        // 没有成交数量
        if(preRecord.getTradeNumber()<=0){
            return;
        }

        // preRecord已配对完成
        int preNotPairNumber = OptionUtils.getNotPairNumber(preRecord);
        if(preNotPairNumber<=0){
            return;
        }

        // 创建配对
        int pairNumber = this.currTradeNumber<=preNotPairNumber ? this.currTradeNumber : preNotPairNumber;
        RecordPair pairInfo = new RecordPair();
        pairInfo.setIndex(this.pairIndex);
        pairInfo.setNumber(pairNumber);
        this.addPairToRecord(preRecord, pairInfo);
        this.pairList.add(pairInfo);

        // 更新配对结算金额
        if(OptionConst.OperationType.TYPE_7.equals(this.currOperationType)){
            // 对于买入，不计算结算金额
        }else{
            double currClearAmount = this.calcClearAmount(this.currRecord, pairNumber);
            double preClearAmount = this.calcClearAmount(preRecord, pairNumber);
            double addDiff = WeistockUtils.add(currClearAmount, preClearAmount);
            double currDiffAmount = this.currRecord.getDiffAmount()==null ? 0 : this.currRecord.getDiffAmount();
            this.currRecord.setDiffAmount(WeistockUtils.add(currDiffAmount, addDiff));
        }

        // 修改变量
        this.currTradeNumber = this.currTradeNumber - pairNumber;
    }

    private void addPairToRecord(OptionRecordDto record, RecordPair pair){
        List<RecordPair> pairList = record.getPairList();
        if(pairList==null){
            pairList = new ArrayList<>();
            record.setPairList(pairList);
        }
        pairList.add(pair);
    }

    private double calcClearAmount(OptionRecordDto record, int pairNumber){
        if(pairNumber==record.getTradeNumber()){
            return record.getClearAmount();
        }
        return WeistockUtils.multi(WeistockUtils.divide(record.getClearAmount(), record.getTradeNumber()), pairNumber);
    }

    public int getCurrTradeNumber(){
        return this.currTradeNumber;
    }

    public void finishRecord(){
        if(this.pairList.size()>0){
            RecordPair currPair = new RecordPair();
            currPair.setIndex(this.pairIndex++);
            int totalNumber = 0;
            for(RecordPair prePair : this.pairList){
                totalNumber += prePair.getNumber();
            }
            currPair.setNumber(totalNumber);
            this.addPairToRecord(this.currRecord, currPair);
        }
    }
}
